<?php
/**
 * WebSocket 服务器
 * 用于实时推送刷脸签到消息到浏览器，实现语音播报
 * 
 * 端口：8779
 * 
 * 使用方法：
 * php websocket_server.php start
 */

require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;
use Workerman\Lib\Timer;

// 创建 WebSocket 服务器
$ws_worker = new Worker("websocket://0.0.0.0:8779");

// 设置进程数
$ws_worker->count = 1;

// 设置进程名称
$ws_worker->name = 'CheckinWebSocketServer';

// 存储所有连接的客户端
$ws_worker->connections = [];

// 当有客户端连接时
$ws_worker->onConnect = function($connection) use ($ws_worker) {
    echo "[" . date('Y-m-d H:i:s') . "] 新客户端连接: {$connection->id}\n";
    
    // 发送欢迎消息
    $connection->send(json_encode([
        'type' => 'welcome',
        'message' => 'WebSocket连接成功',
        'time' => date('Y-m-d H:i:s')
    ], JSON_UNESCAPED_UNICODE));
};

// 当收到客户端消息时
$ws_worker->onMessage = function($connection, $data) use ($ws_worker) {
    echo "[" . date('Y-m-d H:i:s') . "] 收到消息: {$data}\n";
    
    try {
        $message = json_decode($data, true);
        
        if (!$message) {
            $connection->send(json_encode([
                'type' => 'error',
                'message' => '无效的JSON格式'
            ], JSON_UNESCAPED_UNICODE));
            return;
        }
        
        // 处理心跳
        if (isset($message['type']) && $message['type'] === 'ping') {
            $connection->send(json_encode([
                'type' => 'pong',
                'time' => date('Y-m-d H:i:s')
            ], JSON_UNESCAPED_UNICODE));
            return;
        }
        
        // 处理广播消息（从TCP服务器发来的）
        if (isset($message['type']) && $message['type'] === 'broadcast') {
            // 广播给所有连接的客户端
            foreach ($ws_worker->connections as $client_connection) {
                $client_connection->send(json_encode($message['data'], JSON_UNESCAPED_UNICODE));
            }
            echo "[" . date('Y-m-d H:i:s') . "] 已广播消息给 " . count($ws_worker->connections) . " 个客户端\n";
            return;
        }
        
        // 回显消息
        $connection->send(json_encode([
            'type' => 'echo',
            'data' => $message
        ], JSON_UNESCAPED_UNICODE));
        
    } catch (\Exception $e) {
        echo "[错误] " . $e->getMessage() . "\n";
        $connection->send(json_encode([
            'type' => 'error',
            'message' => $e->getMessage()
        ], JSON_UNESCAPED_UNICODE));
    }
};

// 当客户端断开连接时
$ws_worker->onClose = function($connection) {
    echo "[" . date('Y-m-d H:i:s') . "] 客户端断开: {$connection->id}\n";
};

// 当进程启动时
$ws_worker->onWorkerStart = function($worker) {
    echo "\n";
    echo "========================================\n";
    echo "  签到系统 WebSocket 服务器已启动\n";
    echo "========================================\n";
    echo "监听地址: ws://0.0.0.0:8779\n";
    echo "进程ID: " . posix_getpid() . "\n";
    echo "启动时间: " . date('Y-m-d H:i:s') . "\n";
    echo "========================================\n";
    echo "\n";
    echo "前端连接示例：\n";
    echo "const ws = new WebSocket('ws://localhost:8779');\n";
    echo "\n";
    echo "按 Ctrl+C 停止服务\n";
    echo "\n";
    
    // 创建内部通信服务器（用于接收TCP服务器的消息）
    $inner_worker = new Worker('text://0.0.0.0:8780');
    $inner_worker->onMessage = function($connection, $data) use ($worker) {
        echo "[" . date('Y-m-d H:i:s') . "] 收到内部消息: {$data}\n";

        try {
            $message = json_decode($data, true);

            if (!$message) {
                echo "[错误] 无效的JSON格式\n";
                // 关闭连接
                $connection->close();
                return;
            }

            // 广播给所有WebSocket客户端
            if (count($worker->connections) > 0) {
                foreach ($worker->connections as $client_connection) {
                    $client_connection->send(json_encode($message, JSON_UNESCAPED_UNICODE));
                }
                echo "[" . date('Y-m-d H:i:s') . "] 已推送消息给 " . count($worker->connections) . " 个客户端\n";
            } else {
                echo "[提示] 当前没有客户端连接\n";
            }

        } catch (\Exception $e) {
            echo "[错误] " . $e->getMessage() . "\n";
        } finally {
            // 处理完消息后立即关闭连接，防止连接堆积
            $connection->close();
        }
    };

    $inner_worker->listen();
    echo "内部通信端口: 8780 (用于接收TCP服务器消息)\n\n";
};

// 运行所有Worker
Worker::runAll();

